package com.nsoft.html5npub.utils;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import org.simpleframework.xml.core.Persister;

import com.nsoft.html5npub.R;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
import android.os.Environment;
import android.os.Vibrator;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import android.webkit.WebView;

public class utils {
	
	private static DisplayMetrics metrics;
	
	private static String externalPath=Constant.EMPTY;
	private static String fullBasePath=Constant.EMPTY;
	private static String bookPath=Constant.EMPTY;
	private static String historyPath=Constant.EMPTY;
	private static String thumbPath=Constant.EMPTY;
	private static String historyListFile=Constant.EMPTY;
	private static String iconPath=Constant.EMPTY;
	
	public static String getExternalStoragePath(){
		return externalPath;
	}
	
	public static String getFullBasePath(){
		if (fullBasePath.equals(Constant.EMPTY)){
			checkTempFolder();
		}
		return fullBasePath;
	}
	
	public static String getBookPath(){
		if (bookPath.equals(Constant.EMPTY)){
			checkTempFolder();
		}
		return bookPath;
	}
	
	public static String getHistoryPath(){
		if (historyPath.equals(Constant.EMPTY)){
			checkTempFolder();
		}
		return historyPath;
	}
	
	public static String getThumbPath(){
		if (thumbPath.equals(Constant.EMPTY)){
			checkTempFolder();
		}
		return thumbPath;
	}
	
	public static String getHistoryListFile(){
		if (historyPath.equals(Constant.EMPTY)){
			checkTempFolder();
		}
		historyListFile=historyPath+
			Constant.PATH_SPLITTER+
			Constant.UTIL_BOOKLIST_HISTORY_FILE;
		return historyListFile;
	}
	
	public static String getIconPath(){
		if (iconPath.equals(Constant.EMPTY)){
			checkTempFolder();
		}
		return iconPath;
	}
	
	public static boolean checkTempFolder(){
		if (!fullBasePath.equals(Constant.EMPTY)){
			return true;
		}
		boolean isFolderCreated=false;
		
		externalPath=Environment.
				getExternalStorageDirectory().
				getAbsolutePath()+
				Constant.PATH_SPLITTER;
		fullBasePath=externalPath+
				Constant.UTIL_SDCARD_BASEFOLDER_NAME;
		File p=new File(fullBasePath);
		if (!p.exists()){
			p.mkdir();
			isFolderCreated=true;
		}
		bookPath=fullBasePath+
				Constant.PATH_SPLITTER+
				Constant.UTIL_SDCARD_BOOKFOLDER_NAME;
		p=new File(bookPath);
		if (!p.exists()){
			p.mkdir();
			isFolderCreated=true;
		}
		historyPath=fullBasePath+
				Constant.PATH_SPLITTER+
				Constant.UTIL_SDCARD_HISTORYFOLDER_NAME;
		p=new File(historyPath);
		if (!p.exists()){
			p.mkdir();
			isFolderCreated=true;
		}
		thumbPath=historyPath+
				Constant.PATH_SPLITTER+
				Constant.UTIL_SDCARD_THUMBFOLDER_NAME;
		p=new File(thumbPath);
		if (!p.exists()){
			p.mkdir();
			isFolderCreated=true;
		}
		iconPath=fullBasePath+
				Constant.PATH_SPLITTER+
				Constant.UTIL_SDCARD_BOOKFOLDER_NAME+
				Constant.PATH_SPLITTER+
				Constant.UTIL_SDCARD_ICONFOLDER_NAME;
		p=new File(iconPath);
		if (!p.exists()){
			p.mkdir();
			isFolderCreated=true;
		}
		return !isFolderCreated;
	}
	
	public static boolean encodeXml(Object o,File f) 
							throws Exception {
		Persister persister = new Persister();
		persister.write(o,f);
		return true;
	}
	
	public static Object decodeXml(File f,Class<?> c)
							throws Exception {
		Persister persister = new Persister();
		return persister.read(c,f);
	}
	
	public static void showInfo(
			Context ctx,String title,String msg){
		AlertDialog.Builder alert=
				new AlertDialog.Builder(ctx);
		alert.setIcon(R.drawable.ic_info);
		alert.setTitle(title).
			setMessage(msg).
			setPositiveButton(Constant.DIALOG_OK,
				new DialogInterface.OnClickListener() {
					
					@Override
					public void onClick(
							DialogInterface dialog, 
							int which) {
						dialog.cancel();
					}
				}).create().show();
	}
	
	public static void showError(
			Context ctx,String title,String msg){
		AlertDialog.Builder alert=
				new AlertDialog.Builder(ctx);
		alert.setIcon(R.drawable.ic_cancel);
		alert.setTitle(title).
			setMessage(msg).
			setPositiveButton(Constant.DIALOG_OK,
				new DialogInterface.OnClickListener() {
					
					@Override
					public void onClick(
							DialogInterface dialog, 
							int which) {
						dialog.cancel();
					}
				}).create().show();
	}
		
    public static View addView(String content,
    							Context ctx){
		WebView wv=new WebView(ctx);
		wv.loadData(content,"text/html","utf-8");
		return wv;
    }
    
    /**
     * check if network is available before getting to
     * processes like server synchronization or book download
     * 
     * @param c
     * @return
     */
    public static boolean isOnline(Context c) {
        ConnectivityManager cm=(ConnectivityManager)
        		c.getSystemService(
        				Context.CONNECTIVITY_SERVICE);
        NetworkInfo netInfo=cm.getActiveNetworkInfo();
        return netInfo!=null&&
        		netInfo.isConnectedOrConnecting();
    }
    
    /**
     * read bitmap from a file and resize to the expected
     * size image.
     * 
     * @param path
     * @param expWidth
     * @return
     * @throws IOException
     */
	public static Bitmap createThumbnailBitmap(String path,
						int expWidth) throws IOException{
		InputStream is=null;
		
		try{
			is=new FileInputStream(path);
			BitmapFactory.Options o=
					new BitmapFactory.Options();
			o.inJustDecodeBounds = true;
			BitmapFactory.decodeStream(is,null,o);
			is.close();
			
			int scale=1;
			while(o.outWidth/scale/2>=0)
			scale*=2;

			is=new FileInputStream(path);
			BitmapFactory.Options o2= 
					new BitmapFactory.Options();
			o2.inSampleSize=scale;
			o2.inPurgeable=true;
			return BitmapFactory.decodeStream(is,null,o2);
		}catch(IOException ex){
			Log.e("BookUtils.createThumbnailBitmap()",
			ex.getClass()+": "+ex.getMessage());
			throw ex;
		}finally{
			if (is!=null){
			is.close();
			}
		}
	}
    
	/**
	 * 
	 * @param bmpPath
	 * @return
	 * @throws IOException
	 */
	public static Bitmap createBitmap(String bmpPath)
								throws IOException {
		FileInputStream fis=null;
		try{
			fis=new FileInputStream(bmpPath);
			return createBitmap(fis,fis.available());
		}catch(IOException e){
			throw e;
		}finally{
			if (fis!=null)
				fis.close();
		}
	}
    /**
     * create a bitmap from an input stream (probably from
     * Internet) and resize the bitmap to thumb size.
     * @param is
     * @param length
     * @return
     * @throws Exception
     */
	public static Bitmap createBitmap(InputStream is,
						int length) throws IOException{
		BufferedInputStream bis=null;
		
		try{
			bis=new BufferedInputStream(is);
			if (bis.markSupported()){
				int contentLength=length;
				bis.mark(contentLength);
			}
		
			BitmapFactory.Options o=
						new BitmapFactory.Options();
			o.inJustDecodeBounds=true;
			BitmapFactory.decodeStream(bis,null,o);
			if (bis.markSupported()){
				bis.reset();
			}
		
			int scale=1;
			while(o.outWidth/scale/2>=
						Constant.bmp.WIDTH)
				scale*=2;
		
			BitmapFactory.Options o2=
						new BitmapFactory.Options();
			o2.inSampleSize=scale;
			o2.inPurgeable=true;
			
			return BitmapFactory.decodeStream(bis,null,o2);
		}catch(IOException ex){
			Log.e("utils.createBitmap()",
				ex.getClass()+": "+ex.getMessage());
			throw ex;
		}finally{
			if (bis!=null){
				bis.close();
			}
		}
	}
    
    public static void unzipFile(Context c,String zipFile,
    		String outputFolder,boolean updateHtml) 
    							throws IOException{
    	/**
    	 * get device size & dimension metrics
    	 */
    	if (utils.metrics==null&&c!=null){
	    	getDeviceMetrics(c);
    	}
    	
    	byte[] buffer=new byte[1024];
        
    	try{
    		File folder=new File(outputFolder);
	       	if(!folder.exists()){
	       		folder.mkdir();
	       	}
    
	       	ZipInputStream zis=new ZipInputStream(
	       				new FileInputStream(zipFile));
	       	ZipEntry ze=zis.getNextEntry();
	       	String outputFile=Constant.EMPTY;
	       	while(ze!=null){
	       		String fileName=ze.getName();
	       		outputFile=outputFolder+
            			File.separator+fileName;
	       		File newFile=new File(outputFile);
	            new File(newFile.getParent()).mkdirs();
	            FileOutputStream fos=new 
	            		FileOutputStream(newFile);             
	
	            int len;
	            while ((len=zis.read(buffer))>0){
	            	fos.write(buffer,0,len);
	            }
	            fos.close();   
	            
	            if (updateHtml&&outputFile.
	            		endsWith(Constant.UTIL_HTML)){
	            	updateHtml(newFile.getAbsolutePath());
	            }
	            ze=zis.getNextEntry();
	       	}
	       	zis.closeEntry();
	       	zis.close();
   
    	}catch(IOException e){
    		Log.e("utils.unzipFile()",
    			e.getClass()+": "+e.getMessage());
    		throw e;
    	}
    	 	
    }
    
    public static void copySupplierJs(Context c,
			String outputFolder) throws Exception{
    	
    	String outJsPath=outputFolder+
    			Constant.PATH_SPLITTER+
    			Constant.STR_JS+Constant.PATH_SPLITTER+
    			Constant.utils.JS_SUPPLIER_FILE;
    	InputStream is=null;
    	
    	FileOutputStream output=null;
    	try{		
    		is=c.getResources().openRawResource(
    							R.raw.supplier);
			output=new FileOutputStream(outJsPath,false);
    
		    byte[] buff=new byte[1024];
		    int bytesRead=0;
		    while((bytesRead=is.read(buff))!=-1){
		    	output.write(buff,0,bytesRead);
		    }
		    output.flush();
    	}catch(Exception e){
    		throw e;
    	}finally{
    		if (is!=null)
    			is.close();
    		if (output!=null)
    			output.close();
	    }
    }
    
	private static void updateHtml(String htmlFilePath){
		
		if (!htmlFilePath.endsWith(Constant.UTIL_HTML))
			return;
		
		File f=new File(htmlFilePath);
		
        FileInputStream fs=null;
        InputStreamReader in=null;
        BufferedReader br=null;

        StringBuffer sb=new StringBuffer();
        String textinLine;
        String content=Constant.EMPTY;
        
        try{
        	fs=new FileInputStream(f);
            in=new InputStreamReader(fs);
            br=new BufferedReader(in);

            while(true){
            	textinLine=br.readLine();
                if(textinLine==null)
                    break;
                sb.append(textinLine+Constant.CHR_LINEBREAK);
            }
            
            Pattern p=Pattern.compile(
            		Constant.utils.UTIL_ZOOM_METATAG);
            Matcher m=p.matcher(sb.toString());
            String viewport=Constant.EMPTY;
            
            /**
             * change the view-port to adapt to variable devices
             */
            int scale=utils.metrics.densityDpi;
            String modifViewportMeta=
        		(utils.metrics.widthPixels>
        					Constant.pagesize.WIDTH?
    				Constant.utils.UTIL_ZOOM_METATAG2:
    				Constant.utils.UTIL_ZOOM_METATAG1);
            		
            int offs=0;
            while (m.find()){
            	viewport=m.group();
            	offs=sb.indexOf(viewport);
            	sb.replace(offs,offs+viewport.length(),
            			modifViewportMeta.
            				replace(Constant.CHR_REPLACE,
            				Integer.toString((int)scale)));
            }
            
            /**
             * remove java-script tags 
             */
            /**
            separateHtml(htmlFilePath,sb);
            */
            
            /**
             * replace the specified type inside video tags
             */
            content=sb.toString();
            content.replaceAll(Constant.utils.UTIL_TYPE_REMOVAL,
            					Constant.EMPTY);
            
            fs.close();
            in.close();
            br.close();
        }catch (IOException e){
        	Log.e("utils.updateHtml() - read & modify process",
        		e.getClass()+": "+e.getMessage());
        }catch(Exception e1){
        	Log.e("utils.updateHtml.separateHtml()",
            		e1.getClass()+": "+e1.getMessage());
        }

        try{
            FileWriter fstream=new FileWriter(f);
            BufferedWriter outobj=
            		new BufferedWriter(fstream);
            outobj.write(content);
            /**
            outobj.write(sb.toString());
            */
            outobj.close();
        }catch (IOException e){
        	Log.e("utils.updateHtml() - write out process",
        		e.getClass()+": "+e.getMessage());
        }
	}
	
	/**
	private static void separateHtml(String htmlFilePath,
			StringBuffer htmlContent) throws Exception{
	
		String pattern=Constant.utils.JS_PATTERN;
		Pattern p=Pattern.compile(pattern,
					Pattern.MULTILINE|Pattern.DOTALL);
	    Matcher m=p.matcher(htmlContent.toString());
	    
	    String jsTagFound=Constant.EMPTY;
	    int offs,endOffs;
	    String jsFile=Constant.EMPTY;
	    
	    ArrayList<String> jsFileArray=new ArrayList<String>();
	    while (m.find()){
	    	jsTagFound=m.group();
	    	offs=htmlContent.indexOf(jsTagFound);
	    	htmlContent.replace(offs,
	    			offs+jsTagFound.length(),
	    			Constant.EMPTY);
	    	
	    	if (jsTagFound.indexOf(Constant.
	    				utils.JS_LINKED_FILE)>=0){
	    		offs=Constant.utils.JS_LINKED_FILE.length();
	    		endOffs=jsTagFound.indexOf(
	    				Constant.CHR_QUOTE,offs+1);
	    		jsFile=jsTagFound.substring(offs,endOffs);
	    		jsFileArray.add(jsFile);
	    	}
	    }
	    
	    offs=htmlFilePath.lastIndexOf(Constant.PATH_DOT);
	    
	    String outJsModFile=Constant.PATH_DOT+
					Constant.PATH_DOT+
					Constant.PATH_SPLITTER+
					Constant.STR_JS+Constant.PATH_SPLITTER+
					Constant.utils.JS_SUPPLIER_FILE;
	    jsFileArray.add(outJsModFile);
	    
	    String outXmlPath=htmlFilePath.substring(0,offs+1)+
	    								Constant.STR_XML;
	    saveJsToXml(outXmlPath,
	    		jsFileArray.toArray(new String[]{}));
	    
	}
	*/
	
	/**
	private static String saveJsToFile(String outJsPath,
			String jsCode) throws Exception{
		File jsFile = new File(outJsPath);
		String jsFileName = jsFile.getName();
		String parentDir = Constant.PATH_DOT + Constant.PATH_SPLITTER;
		if (!jsFile.exists()) {
			FileOutputStream fos = new FileOutputStream(outJsPath);
			OutputStreamWriter osw = new OutputStreamWriter(fos,
					Constant.STR_UTF8);

			osw.write(jsCode);

			osw.close();
			fos.close();
		}
		return parentDir + jsFileName;
	}
	*/
	
	/**
	private static void saveJsToXml(String outXmlPath,
				String[] jsFiles) throws Exception {

		DocumentBuilderFactory docFactory= 
					DocumentBuilderFactory.newInstance();
		DocumentBuilder docBuilder = null;
		try {
			docBuilder=docFactory.newDocumentBuilder();
			Document doc=docBuilder.newDocument();
			Element rootElement=doc.createElement(
							Constant.utils.XML_JS_TAG);
			doc.appendChild(rootElement);
			Element files=doc.createElement(
						Constant.utils.XML_JSFILES);
			rootElement.appendChild(files);
			Element file=null;
			for (int i=0;i<jsFiles.length;i++) {
				file=doc.createElement(
						Constant.utils.XML_JSFILE);
				file.setTextContent(jsFiles[i]);
				files.appendChild(file);
			}

			TransformerFactory transformerFactory=
						TransformerFactory.newInstance();
			Transformer transformer=transformerFactory.
										newTransformer();
			DOMSource source=new DOMSource(doc);
			StreamResult result=new StreamResult(
								new File(outXmlPath));
			transformer.transform(source,result);

		} catch (Exception e) {
			throw e;
		} finally {
			//clear buffer
		}
	}
	*/
	
	/**
     * delete an non-empty folder (recursively)
     * @param file
     * @throws IOException
     */
    public static void delete(File file) 
    			throws IOException{
     	if(file.isDirectory()){
     		if(file.list().length==0){
     			file.delete();
    		}else{
    			String files[]=file.list();
    			for (String temp:files){
    				File fileDelete=new File(file,temp);
    				delete(fileDelete);
    			}

    			if(file.list().length==0){
    				file.delete();
    			}
    		}
     	}else{
    		file.delete();
    	}
    }
    
    public static DisplayMetrics getDeviceMetrics(){
    	return utils.metrics;
    }
    
    public static void vibrate(Context c,int duration){
    	Vibrator vibrator = (Vibrator)c.getSystemService(
    					Context.VIBRATOR_SERVICE);
    	vibrator.vibrate(duration);
    }
    
    /**
     * get device metrics. 
     * get it only one during the application life
     * 
     * @param c
     * @return
     */
    public static DisplayMetrics getDeviceMetrics(Context c){
    	if (utils.metrics==null){
	    	utils.metrics=new DisplayMetrics();    
			((Activity)c).getWindowManager().
				getDefaultDisplay().
					getMetrics(utils.metrics);
    	}
    	return utils.metrics;
    }
    
    public static DisplayMetrics getRealMetrics(Context c){
    	if (utils.metrics==null){
    	utils.metrics=new DisplayMetrics();    
		((Activity)c).getWindowManager().
			getDefaultDisplay().
				getRealMetrics(utils.metrics);
    	}
		return utils.metrics;
    }
    
    public static int[] getGridSizeLayout(Context c){
    	int[] size=new int[5];
    	DisplayMetrics dm=(Build.VERSION.SDK_INT>=
    				Build.VERSION_CODES.HONEYCOMB)?
    					utils.getRealMetrics(c):
    					utils.getDeviceMetrics(c);

    	int deviceHeight=dm.widthPixels<dm.heightPixels?
				dm.heightPixels:dm.widthPixels;
		int deviceWidth=dm.widthPixels<dm.heightPixels?
				dm.widthPixels:dm.heightPixels;
		if (deviceHeight==Constant.grid.DEVICE_H800){
	    	size[0]=Constant.grid.SCALE_TOP_H800;
	    	size[1]=Constant.grid.SCALE_CELL_H800;
	    	size[2]=Constant.grid.SCALE_IMAGE_H800;
    	}else if (deviceHeight==Constant.grid.DEVICE_H1024){
    		
    	}else if (deviceHeight==Constant.grid.DEVICE_H1280){
    		size[0]=Constant.grid.SCALE_TOP_H1280;
	    	size[1]=Constant.grid.SCALE_CELL_H1280;
	    	size[2]=Constant.grid.SCALE_IMAGE_H1280;
    	}
    	size[3]=deviceWidth;
    	size[4]=deviceHeight;
    	return size;
    }
}
